/**
 * 用户服务层
 * 处理用户相关的业务逻辑
 */

import { User, sequelize } from '../models/index.js';
import { hashPassword, comparePassword, validatePasswordStrength } from '../utils/password.js';
import { generateToken } from '../utils/jwt.js';
import { AppError } from '../utils/appError.js';

/**
 * 注册新用户
 * @param {string} username - 用户名
 * @param {string} password - 密码
 * @param {string} gradeLevel - 年级级别
 * @returns {Promise<{success: boolean, data: object, message: string}>}
 */
export const register = async (username, password, gradeLevel) => {
  // 1. 输入验证
  if (!username || typeof username !== 'string' || username.trim().length === 0) {
    throw new AppError('INVALID_INPUT', '用户名不能为空', 400);
  }

  if (username.length < 3 || username.length > 20) {
    throw new AppError('INVALID_INPUT', '用户名长度必须在3-20个字符之间', 400);
  }

  if (!password || typeof password !== 'string') {
    throw new AppError('INVALID_INPUT', '密码不能为空', 400);
  }

  // 验证密码强度
  const passwordValidation = validatePasswordStrength(password);
  if (!passwordValidation.valid) {
    throw new AppError('WEAK_PASSWORD', passwordValidation.errors.join('; '), 400);
  }

  const validGradeLevels = ['primary', 'middle', 'high'];
  if (!gradeLevel || !validGradeLevels.includes(gradeLevel)) {
    throw new AppError('INVALID_INPUT', '年级级别必须是: primary, middle, high 之一', 400);
  }

  // 2. 检查用户名是否已存在
  const existingUser = await User.findOne({ where: { username: username.trim() } });
  if (existingUser) {
    throw new AppError('USERNAME_EXISTS', '用户名已被使用', 409);
  }

  // 3. 哈希密码
  const passwordHash = await hashPassword(password);

  // 4. 创建用户（使用事务）
  const transaction = await sequelize.transaction();
  try {
    const user = await User.create(
      {
        username: username.trim(),
        passwordHash,
        gradeLevel,
      },
      { transaction }
    );

    await transaction.commit();

    // 5. 生成JWT令牌
    const token = generateToken({
      userId: user.id,
      username: user.username,
      gradeLevel: user.gradeLevel,
    });

    // 6. 返回用户信息和token
    return {
      token,
      user: {
        id: user.id,
        username: user.username,
        gradeLevel: user.gradeLevel,
        createdAt: user.createdAt,
      },
    };
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

/**
 * 用户登录
 * @param {string} username - 用户名
 * @param {string} password - 密码
 * @returns {Promise<{success: boolean, data: object, message: string}>}
 */
export const login = async (username, password) => {
  // 1. 输入验证
  if (!username || typeof username !== 'string' || username.trim().length === 0) {
    throw new AppError('INVALID_INPUT', '用户名不能为空', 400);
  }

  if (!password || typeof password !== 'string' || password.length === 0) {
    throw new AppError('INVALID_INPUT', '密码不能为空', 400);
  }

  // 2. 查找用户
  const user = await User.findOne({ where: { username: username.trim() } });
  if (!user) {
    throw new AppError('INVALID_CREDENTIALS', '用户名或密码错误', 401);
  }

  // 3. 验证密码
  const isPasswordValid = await comparePassword(password, user.passwordHash);
  if (!isPasswordValid) {
    throw new AppError('INVALID_CREDENTIALS', '用户名或密码错误', 401);
  }

  // 4. 更新最后登录时间
  await user.update({ lastLoginAt: new Date() });

  // 5. 生成JWT令牌
  const token = generateToken({
    userId: user.id,
    username: user.username,
    gradeLevel: user.gradeLevel,
  });

  // 6. 返回用户信息和令牌（直接返回数据，不包装）
  return {
    user: {
      id: user.id,
      username: user.username,
      gradeLevel: user.gradeLevel,
      lastLoginAt: user.lastLoginAt,
    },
    token,
  };
};

/**
 * 根据ID获取用户信息
 * @param {string} userId - 用户ID
 * @returns {Promise<{success: boolean, data: object, message: string}>}
 */
export const getUserById = async (userId) => {
  // 1. 输入验证
  if (!userId) {
    throw new AppError('INVALID_INPUT', '用户ID不能为空', 400);
  }

  // 2. 查找用户
  const user = await User.findByPk(userId, {
    attributes: { exclude: ['passwordHash'] }, // 排除密码字段
  });

  if (!user) {
    throw new AppError('USER_NOT_FOUND', '用户不存在', 404);
  }

  // 3. 返回用户信息
  return {
    success: true,
    data: {
      id: user.id,
      username: user.username,
      gradeLevel: user.gradeLevel,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt,
      lastLoginAt: user.lastLoginAt,
    },
    message: '获取用户信息成功',
  };
};

/**
 * 更新用户资料
 * @param {string} userId - 用户ID
 * @param {object} updates - 要更新的字段
 * @param {string} [updates.username] - 新用户名
 * @param {string} [updates.gradeLevel] - 新年级级别
 * @param {string} [updates.password] - 新密码
 * @returns {Promise<{success: boolean, data: object, message: string}>}
 */
export const updateProfile = async (userId, updates) => {
  // 1. 输入验证
  if (!userId) {
    throw new AppError('INVALID_INPUT', '用户ID不能为空', 400);
  }

  if (!updates || typeof updates !== 'object' || Object.keys(updates).length === 0) {
    throw new AppError('INVALID_INPUT', '更新内容不能为空', 400);
  }

  // 2. 查找用户
  const user = await User.findByPk(userId);
  if (!user) {
    throw new AppError('USER_NOT_FOUND', '用户不存在', 404);
  }

  // 3. 准备更新数据
  const updateData = {};

  // 验证并处理用户名更新
  if (updates.username !== undefined) {
    if (typeof updates.username !== 'string' || updates.username.trim().length === 0) {
      throw new AppError('INVALID_INPUT', '用户名不能为空', 400);
    }

    if (updates.username.length < 3 || updates.username.length > 50) {
      throw new AppError('INVALID_INPUT', '用户名长度必须在3-50个字符之间', 400);
    }

    // 检查新用户名是否已被使用
    if (updates.username.trim() !== user.username) {
      const existingUser = await User.findOne({
        where: { username: updates.username.trim() },
      });
      if (existingUser) {
        throw new AppError('USERNAME_EXISTS', '用户名已被使用', 409);
      }
      updateData.username = updates.username.trim();
    }
  }

  // 验证并处理年级级别更新
  if (updates.gradeLevel !== undefined) {
    const validGradeLevels = ['primary', 'middle', 'high'];
    if (!validGradeLevels.includes(updates.gradeLevel)) {
      throw new AppError('INVALID_INPUT', '年级级别必须是: primary, middle, high 之一', 400);
    }
    updateData.gradeLevel = updates.gradeLevel;
  }

  // 验证并处理密码更新
  if (updates.password !== undefined) {
    if (typeof updates.password !== 'string') {
      throw new AppError('INVALID_INPUT', '密码格式错误', 400);
    }

    // 验证密码强度
    const passwordValidation = validatePasswordStrength(updates.password);
    if (!passwordValidation.valid) {
      throw new AppError('WEAK_PASSWORD', passwordValidation.errors.join('; '), 400);
    }

    updateData.passwordHash = await hashPassword(updates.password);
  }

  // 4. 使用事务更新用户
  const transaction = await sequelize.transaction();
  try {
    await user.update(updateData, { transaction });
    await transaction.commit();

    // 5. 返回更新后的用户信息（不包含密码）
    return {
      success: true,
      data: {
        id: user.id,
        username: user.username,
        gradeLevel: user.gradeLevel,
        updatedAt: user.updatedAt,
      },
      message: '更新用户资料成功',
    };
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

/**
 * 根据用户名查找用户
 * @param {string} username - 用户名
 * @returns {Promise<{success: boolean, data: object, message: string}>}
 */
export const getUserByUsername = async (username) => {
  // 1. 输入验证
  if (!username || typeof username !== 'string' || username.trim().length === 0) {
    throw new AppError('INVALID_INPUT', '用户名不能为空', 400);
  }

  // 2. 查找用户
  const user = await User.findOne({
    where: { username: username.trim() },
    attributes: { exclude: ['passwordHash'] },
  });

  if (!user) {
    throw new AppError('USER_NOT_FOUND', '用户不存在', 404);
  }

  // 3. 返回用户信息
  return {
    success: true,
    data: {
      id: user.id,
      username: user.username,
      gradeLevel: user.gradeLevel,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt,
      lastLoginAt: user.lastLoginAt,
    },
    message: '获取用户信息成功',
  };
};

/**
 * 删除用户
 * @param {string} userId - 用户ID
 * @returns {Promise<{success: boolean, message: string}>}
 */
export const deleteUser = async (userId) => {
  // 1. 输入验证
  if (!userId) {
    throw new AppError('INVALID_INPUT', '用户ID不能为空', 400);
  }

  // 2. 查找用户
  const user = await User.findByPk(userId);
  if (!user) {
    throw new AppError('USER_NOT_FOUND', '用户不存在', 404);
  }

  // 3. 使用事务删除用户
  const transaction = await sequelize.transaction();
  try {
    await user.destroy({ transaction });
    await transaction.commit();

    return {
      success: true,
      message: '删除用户成功',
    };
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

export default {
  register,
  login,
  getUserById,
  updateProfile,
  getUserByUsername,
  deleteUser,
};

